package cn.bugstack.config;

import cn.bugstack.types.annotations.DCCValue;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.apache.curator.framework.CuratorFramework;
import org.apache.curator.framework.recipes.cache.CuratorCache;
import org.springframework.aop.framework.AopProxyUtils;
import org.springframework.aop.support.AopUtils;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.BeanPostProcessor;
import org.springframework.context.annotation.Configuration;
import java.lang.reflect.Field;
import java.util.HashMap;
import java.util.Map;

@Slf4j
@Configuration
public class DCCValueBeanFactory implements BeanPostProcessor {
    private static final String BASE_CONFIG_PATH = "/big-market-dcc";
    private static final String BASE_CONFIG_PATH_CONFIG = BASE_CONFIG_PATH + "/config";

    private final CuratorFramework client;

    private final Map<String, Object> dccObjGroup = new HashMap<>();

    public DCCValueBeanFactory(CuratorFramework client) throws Exception {
        this.client = client;
        // 节点判断
        if (null == client.checkExists().forPath(BASE_CONFIG_PATH_CONFIG)) {
            client.create().creatingParentContainersIfNeeded().forPath(BASE_CONFIG_PATH_CONFIG);
            log.info("DCC 节点监听 base node {} not absent create new done!", BASE_CONFIG_PATH_CONFIG);
        }
        // 构建缓存
        CuratorCache curatorCache = CuratorCache.build(client, BASE_CONFIG_PATH_CONFIG);
        curatorCache.start();
        // 进行监听
        curatorCache.listenable().addListener((type, oldData, data) -> {
            switch (type) {
                // 只监听节点的变化
                case NODE_CHANGED:
                    String dccValuePath = data.getPath();
                    Object objBean = dccObjGroup.get(dccValuePath);
                    if (null == objBean) {
                        return;
                    }
                    try {
                        Field field = objBean.getClass().getDeclaredField(dccValuePath.substring(dccValuePath.lastIndexOf("/") + 1));
                        field.setAccessible(true);
                        field.set(objBean, new String(data.getData()));
                        field.setAccessible(false);
                    } catch (Exception e) {
                        throw new RuntimeException(e);
                    }
                    break;
                default:
                    break;
            }
        });
    }

    @Override
    public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
        // 获取bean的class对象
        Class<?> targetBeanClass = bean.getClass();
        Object targetBeanObject = bean;

        if (AopUtils.isAopProxy(bean)) {
            targetBeanClass = AopUtils.getTargetClass(bean);
            targetBeanObject = AopProxyUtils.getSingletonTarget(bean);
        }
        // 得到bean对象的所有字段值
        Field[] fields = targetBeanClass.getDeclaredFields();
        for (Field field : fields) {
            // 如果当前字段被@DCCValue注解修饰
            if (field.isAnnotationPresent(DCCValue.class)) {
                DCCValue dccValue = field.getAnnotation(DCCValue.class);
                String value = dccValue.value();
                // 如果value没有被初始化
                if (StringUtils.isBlank(value)) {
                    throw new RuntimeException(field.getName() + " @DCCValue is not config value config case 「isSwitch/isSwitch:1」");
                }
                String[] splits = value.split(":");
                String key = splits[0];
                String defaultValue = splits.length == 2 ? splits[1] : null;
                try {
                    // 判断当前节点是否存在，不存在则创建出 Zookeeper 节点
                    String keyPath = BASE_CONFIG_PATH_CONFIG.concat("/").concat(key);
                    if (null==client.checkExists().forPath(keyPath)){
                        client.create().creatingParentContainersIfNeeded().forPath(keyPath);
                        if (StringUtils.isNotBlank(defaultValue)){
                            field.setAccessible(true);
                            field.set(targetBeanObject,defaultValue);
                            field.setAccessible(false);
                            log.info("DCC 节点监听 创建节点 {}", keyPath);
                        }
                    }else {
                        String configValue = new String(client.getData().forPath(keyPath));
                        if (StringUtils.isNotBlank(configValue)){
                            field.setAccessible(true);
                            field.set(targetBeanObject,configValue);
                            field.setAccessible(false);
                            log.info("DCC 节点监听 设置配置 {} {} {}", keyPath, field.getName(), configValue);
                        }
                    }
                }catch (Exception e){
                    throw new RuntimeException(e);
                }
                dccObjGroup.put(BASE_CONFIG_PATH_CONFIG.concat("/").concat(key), targetBeanObject);
            }
        }
        return bean;
    }
}
